/*
 * @Author: intellectual-seeker 3336339701@qq.com
 * @Date: 2025-08-04 11:53:41
 * @LastEditors: intellectual-seeker 3336339701@qq.com
 * @LastEditTime: 2025-08-07 21:14:55
 * @FilePath: /code/lesson25/test1/processpool.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
#include <stdlib.h>
#include "task.hpp"
#include <errno.h>
#include <string.h>

enum
{
    UsageErr = 1,//指令格式
    ArgErr,      //进程数合法性
    PipeErr
};

void Usage(const std::string process)
{
    std::cout << "Usage:\n\t" << process << " sub_process_num\n" << std::endl;
}

class Channel
{
public:
    Channel(pid_t sub_process_id, int wfd, std::string name)
        :_sub_process_id(sub_process_id)
        ,_wfd(wfd)
        ,_name(name)
    {}

    int wfd()
    {
        return _wfd;
    }
    
    const std::string name()
    {
        return _name;
    }

    pid_t pid()
    {
        return _sub_process_id;
    }

    void Debug()
    {
        std::cout << _name << " subprocess_id: " << _sub_process_id << " wfd: " << _wfd << std::endl;
    }

    ~Channel()
    {}

private:
    pid_t _sub_process_id;//管道链接的子进程pid
    int _wfd;             //写端文件fd
    std::string _name;    //标识文件的名字
};

class ProcessPool
{
public:
    ProcessPool(int sub_process_num)
        :_sub_process_num(sub_process_num)
    {}

    int CreateProcess(work_t worker)
    {
        std::vector<int> fds;
        for(int i = 0; i < _sub_process_num; i++)
        {
            //管道创建先于子进程创建之前！
            //创建管道
            int pipefd[2];
            int n = pipe(pipefd);
            if(n < 0) return PipeErr;

            //创建子进程
            pid_t fd = fork();

            // int pipefd[2];
            // int n = pipe(pipefd);
            // if(n < 0) return PipeErr;

            //子进程 'r'
            if(fd == 0)
            {
                //处理子进程文件描述符bug 没有显示与效果
                // for(int i = 0; i < fds.size(); i++)
                // {
                //     close(fds[i]);
                // }

                //std::cout << "child-pipefd[0]: " << pipefd[0] << " pipefd[1]: " << pipefd[1] << std::endl;
                std::cout << "fd: ";
                for(int i = 0; i < fds.size(); i++)
                {
                    std::cout << fds[i] << ' ';
                    close(fds[i]);
                }
                std::cout << std::endl;

                close(pipefd[1]);
                dup2(pipefd[0], 0);//将'r'端的文件描述符重定向
                worker(pipefd[0]);

                exit(0);
            }

            sleep(1);//每创建一个子进程就停顿一下，便于观察

            //父进程 'w'
            close(pipefd[0]);

            //std::cout << "parent-pipefd[0]: " << pipefd[0] << " pipefd[1]: " << pipefd[1] << std::endl;

            std::string name = "channel-" + std::to_string(i);
            //channels.push_back(Channel(getpid(), pipefd[1], name));
            channels.push_back(Channel(fd, pipefd[1], name));

            fds.push_back(pipefd[1]);
        }

        return 0;
    }

    //rs轮询分配
    int NextChannel()
    {
        static int next = 0;
        int pos = next++;
        next %= channels.size();

        return pos;
    }

    void SendTaskCode(int channel, size_t commandcode)
    {
        int wfd = channels[channel].wfd();
        std::cout << channels[channel].name() << " commandcode is " << commandcode 
        << " wfd: " << wfd << std::endl;
        write(wfd, &commandcode, sizeof(commandcode));

        //sleep(1);
    }

    void KillAll()
    {
        //为什么没有关闭所有子程序的写端管道，子程序还是退出了
        //当没有写端管道关闭，则让子程序退出，子程序退出后进行回收
        for(int i = 0; i < channels.size(); i++)
        {
            close(channels[i].wfd());
            pid_t rid = waitpid(channels[i].pid(), nullptr, 0);
            pid_t id = channels[i].pid();

            if(rid == id)
            {
                std::cout << "rid: " << rid << " sucess..." << std::endl;
            }
            else
            {
                std::cout << "id: " << id << " rid: " << rid << " errno: " << strerror(errno) << std::endl;
            }
        }

        // std::cout << "quit now..." << std::endl;
    }

    void PrintDebug()
    {
        for(auto e : channels)
        {
            e.Debug();
        }
    }

    ~ProcessPool()
    {}

private:
    std::vector<Channel> channels;
    int _sub_process_num;
};

void CtrlProcess(ProcessPool* processpool_ptr, int cnt)
{
    while(cnt--)
    {
        size_t commandcode = NextTask();
        int channel = processpool_ptr->NextChannel();

        processpool_ptr->SendTaskCode(channel, commandcode);

        sleep(1);
    }
}

//进程池：创建 => 控制 => 回收
int main(int argc, char* argv[])
{
    if(argc != 2)
        Usage(argv[0]);
    
    srand((size_t)time(nullptr));

    int subprocess_num = std::stoi(argv[1]);
    //int subprocess_num = 5;
    if(subprocess_num <= 0) return ArgErr;

    ProcessPool* processpool_ptr = new ProcessPool(subprocess_num);
    processpool_ptr->CreateProcess(worker);

    //sleep(100);

    //processpool_ptr->PrintDebug();
    CtrlProcess(processpool_ptr, 5);

    processpool_ptr->KillAll();

    std::cout << "quit now..." << std::endl;

    delete processpool_ptr;
    
    return 0;
}